﻿package pers.sakurasora.calendar;

import java.util.Calendar;

import pers.sakurasora.calendar.util.DateUtil;
import pers.sakurasora.calendar.util.InputFormatUtil;

/**
 * @FileName DateConversion.java 
 * @author SakuraSora
 * @Email 1468071675@qq.com
 * @DateTime 2019年1月14日 下午7:28:02
 *
 * @Description
 *				日期转换：输入一个8位数字的日期，输出该日期是星期几（以1970年1月1日为参照）
 */
public class DateConversion {
	/**
	 * 参照年份:1970年
	 */
	private final int REFERENCE_YEAR = 1970;
	/**
	 * 参照月份：1月
	 */
	private final int REFERENCE_MONTH = 1;
	/**
	 * 参照日：1号
	 */
	private final int REFERENCE_DATE = 1;
	/**
	 * 如果参照日期是星期天，REFERENCE_WEEK==0;
	 * 如果参照日期是星期一，REFERENCE_WEEK==1;
	 * ......
	 * 如果参照日期是星期六，REFERENCE_WEEK==6;
	 */
	private final int REFERENCE_WEEK = 4; // 1970年1月1日是星期四
	/**
	 * 存放星期的字符串数组(常量)
	 */
	private final String[] WEEK = {"星期天","星期一","星期二","星期三","星期四","星期五","星期六"};
	/**
	 * 年份
	 */
	private Integer iYear;
	/**
	 * 月份
	 */
	private Integer iMonth;
	/**
	 * 日
	 */
	private Integer iDate;
	/**
	 * 与参照日期相隔的天数
	 */
	private int iDistanceDay;
	
	public DateConversion() 
	{
		super();
	}

	/**
	 * 有参构造函数：通过给定日历字段设置值来构造日期，利用Calendar的容错性，每个时间字段可接受超出它允许范围的值
	 * @param iYear 年
	 * @param iMonth 月
	 * @param iDate 日
	 */
	public DateConversion(int iYear, int iMonth, int iDate) 
	{
		super();
		Calendar calendar = Calendar.getInstance();
		calendar.setLenient(true); // 开启Calendar的容错性
		calendar.set(iYear, iMonth, iDate);
		this.iYear = calendar.get(Calendar.YEAR);
		this.iMonth = calendar.get(Calendar.MONTH);
		this.iDate = calendar.get(Calendar.DATE);
	}
	
	/**
	 * 获取日期转换结果<br>
	 * 该方法必须通过字符串传入一个日期（由8位数字组成的合法日期）
	 * @param sDate 日期字符串
	 * @return 转换结果
	 * @throws Exception
	 */
	public String getDateConversionResult(String sDate)
        throws Exception
	{
		int index = -1;
		getDistanceDay(sDate);
		index = (this.iDistanceDay + REFERENCE_WEEK) % 7;
		return WEEK[index];
	}
	
	/**
	 * 计算传入的日期字符串与参照日期（1970年1月1日）相隔多少天<br>
	 * 对传入日期字符串的合法性进行验证<br>
	 * @param sDate 日期字符串
	 * @return 相隔天数
	 * @throws Exception 
	 */
	public int getDistanceDay(String sDate)
        throws Exception 
	{
		if (InputFormatUtil.dateCheck(sDate)) {
			this.iYear = Integer.parseInt(sDate.substring(0, 4)); // 注意不是sDate.substring(0, 3)
			this.iMonth = Integer.parseInt(sDate.substring(4, 6));
			this.iDate = Integer.parseInt(sDate.substring(6, 8));
			/**
			 * 保证日期是参照日期之后的（包括参照日期）
			 */
			if (this.iYear < REFERENCE_YEAR || (this.iYear == REFERENCE_YEAR && this.iMonth < REFERENCE_MONTH) || (this.iYear == REFERENCE_YEAR && this.iMonth == REFERENCE_MONTH && this.iDate < REFERENCE_DATE)) {
				throw new Exception("当前不支持" + REFERENCE_YEAR +"年" + REFERENCE_MONTH + "月" + REFERENCE_DATE + "日之前的日期转换！");
			}
			getDistanceDay();
		}
		return 0;
	}
	
	/**
	 * 获取日期转换结果<br>
	 * 该方法必须通过DateConversion(iYear, iMonth, iDate)传入一个日期
	 * @return 转换结果
	 * @throws Exception 
	 */
	public String getDateConversionResult() throws Exception 
	{
		int index = -1;
		/**
		 * 保证日期是参照日期之后的（包括参照日期）
		 */
		if (this.iYear < REFERENCE_YEAR || (this.iYear == REFERENCE_YEAR && this.iMonth < REFERENCE_MONTH) || (this.iYear == REFERENCE_YEAR && this.iMonth == REFERENCE_MONTH && this.iDate < REFERENCE_DATE)) {
			throw new Exception("当前不支持" + REFERENCE_YEAR + "年" + REFERENCE_MONTH + "月" + REFERENCE_DATE + "日之前的日期转换！");
		}
		iDistanceDay = getDistanceDay();
		index = (this.iDistanceDay + REFERENCE_WEEK) % 7;
		return WEEK[index];
	}
	
	/**
	 * 计算对象的日期与参照日期（1970年1月1日）相隔多少天<br>
	 * 该方法必须通过DateConversion(iYear, iMonth, iDate)传入一个日期
	 * @return 相隔天数
	 * @throws Exception 
	 */
	public int getDistanceDay()
        throws Exception 
	{
		this.iDistanceDay = 0;
		
		/**
		 * 1、只考虑年份（年份比参照年份大多少年，days加多少年的天数；如果是同年，days不增加。如：参照日期为1970年1月1日，传入日期为2019年2月15日，计算2019年1月1日与1970年1月1日相隔多少天）<br>
		 * 2、再考虑月份（月份比参照月份大多少月（如：2月比1月年大1月），days加多少月的天数；如果是同月，days不增加。如：参照日期为1970年1月1日，传入日期为2019年2月15日，计算[2019年]2月1日与[2019年]1月1日相隔多少天）<br>
		 * 3、最后考虑日（日比参照日大多少天，days加多少天；如果是同日，days不增加。如：参照日期为1970年1月1日，传入日期为2019年2月15日，计算[2019年2月]15号与[2019年1月]1号相隔多少天）<br>
		 * 4、如果参照日期的月份>1，减去多加的天数
		 */
		for (int year = REFERENCE_YEAR; year < this.iYear; year++) {
			if (DateUtil.isLeapYear(year)) {
				this.iDistanceDay += 366;
			} else {
				this.iDistanceDay += 365;
			}
		}
		
		for (int month = REFERENCE_MONTH; month < this.iMonth; month++) {
			this.iDistanceDay += DateUtil.getDaysOfMonth(iYear, month);
		}
		
		this.iDistanceDay += (iDate -REFERENCE_DATE);
		
		if (this.REFERENCE_MONTH > 1) {
			for (int month = 1; month < REFERENCE_MONTH; month++) {
				this.iDistanceDay -= DateUtil.getDaysOfMonth(REFERENCE_YEAR, month);
			}
		}
		return this.iDistanceDay;
	}

	public Integer getiYear() {
		return iYear;
	}

	public Integer getiMonth() {
		return iMonth;
	}

	public Integer getiDate() {
		return iDate;
	}
	
}
